package com.health.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.health.entity.*;
import com.health.mapper.FoodInfoMapper;
import com.health.mapper.UserMapper;
import com.health.service.HealthService;
import com.health.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class HealthServiceImpl extends ServiceImpl<FoodInfoMapper, FoodInfo> implements HealthService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private FoodInfoMapper foodInfoMapper;

    @Override
    public String getDiseaseAssessInfo(Integer userId) {
        UserModel loginUser = userMapper.selectById(userId);
        if(loginUser == null){
            return null;
        }

        // BMI
        Double bmi = loginUser.getBMI();
        // 低血压值
        Double hypotensiveValue = Double.parseDouble(loginUser.getHypotensiveValue());
        // 高血压值
        Double hypertensiveValue = Double.parseDouble(loginUser.getHypertensiveValue());
        // 血糖值
        Double bloodGlucoseValue = Double.parseDouble(loginUser.getBloodGlucoseValue());
        // 血脂值
        Double bloodLipidValue = Double.parseDouble(loginUser.getBloodLipidValue());


        double bmiScore = (bmi - HealthStandardValue.BMI) * 5;
        double hypotensiveScore = ((hypotensiveValue - HealthStandardValue.BLOOD_PRESSURES_LOW)
                + (hypertensiveValue - HealthStandardValue.BLOOD_PRESSURES_HIGH)) * 0.5;
        double bloodGlucoseScore = (bloodGlucoseValue - HealthStandardValue.BLOOD_GLUCOSE) * 10;
        double bloodLipidScore = (bloodLipidValue - HealthStandardValue.BLOOD_LIPIDS) * 10;

        HealthGrade healthGrade = evaluateHealth(bmiScore, hypotensiveScore, bloodGlucoseScore, bloodLipidScore);

        Integer healthLevel = null;

        switch (healthGrade){
            case IDEAL:
                healthLevel = 1;
            case GOOD:
                healthLevel = 2;
            case MODERATELY_UNHEALTHY:
                healthLevel = 3;
            case MILDLY_UNHEALTHY:
                healthLevel = 4;
            case SERIOUSLY_UNHEALTHY:
                healthLevel = 5;
            case HIGH_RISK:
                healthLevel = 6;
        }

        String illLevel = null;
        if(healthLevel == 1){
            illLevel = "低风险轻微疾病";
        }else if(healthLevel == 2){
            illLevel = "低风险中度疾病";
        }else if(healthLevel == 3){
            illLevel = "低风险重度疾病";
        }else if(healthLevel == 4){
            illLevel = "高风险轻微疾病";
        }else if(healthLevel == 5){
            illLevel = "高风险中度疾病";
        }else if(healthLevel == 6){
            illLevel = "高风险重度疾病";
        }

        return "BMI: " + bmi + "<br><br>" +
                "最低血压: " + hypotensiveValue + "<br><br>" +
                "最高血压: " + hypertensiveValue + "<br><br>" +
                "血   糖: " + bloodGlucoseValue + "<br><br>" +
                "血   脂: " + bloodLipidValue + "<br><br>" +
                "根据健康指标, 评估疾病风险为: " + illLevel + "<br><br>";
    }

    @Override
    public String getHealthLevelInfo(Integer userId) {
        UserModel loginUser = userMapper.selectById(userId);
        if(loginUser == null){
            return null;
        }

        // 获取50米短跑时间
        Double meterDashTime = Double.parseDouble(loginUser.getMeterDashTime());
        // 获取引体向上的次数
        Integer pullUpTimes = Integer.parseInt(loginUser.getPullUpTimes());
        // 获取俯卧撑的次数
        Integer pushUpTimes = Integer.parseInt(loginUser.getPushUpTimes());

        Double meterDashScore = (HealthStandardValue.METER_DASH_TIMER - meterDashTime) * 50;
        Double pullUpScore = (pullUpTimes - HealthStandardValue.PULL_UP_TIMES) * 0.5;
        Double pushUpScore = (pushUpTimes - HealthStandardValue.PUSH_UP_TIMES) * 0.5;

        int mointLevel = this.getMointLevel(meterDashScore, pullUpScore, pushUpScore);

        return "50米短跑耗时: " + meterDashTime + "<br><br>" +
                "引体向上次数: " + pullUpTimes + "<br><br>" +
                "俯卧撑次数: " + pushUpTimes + "<br><br>" +
                "根据运动能力评估健康等级为 " + mointLevel + "级<br><br>";
    }

    /**
     * 运动推荐
     * @param userId
     * @return
     */
    @Override
    public String motionRecommend(Integer userId) {
        Map<Integer, String> motionMap = new HashMap<>();
        motionMap.put(1, "推荐您每天进行30分钟的慢跑或游泳, 适应之后可以慢慢增加锻炼时间.");
        motionMap.put(2, "推荐您每天进行45分钟的慢跑或游泳, 适应之后可以慢慢增加锻炼时间.");
        motionMap.put(3, "推荐您每天进行60分钟的慢跑或游泳, 适应之后可以慢慢增加锻炼时间.");
        motionMap.put(4, "推荐您每天进行30分钟的快跑冲刺或攀岩,体操, 适应之后可以慢慢增加锻炼时间.");
        motionMap.put(5, "推荐您每天进行45分钟的快跑冲刺或攀岩,体操, 适应之后可以慢慢增加锻炼时间.");
        motionMap.put(6, "推荐您每天进行60分钟的快跑冲刺或攀岩,体操, 适应之后可以慢慢增加锻炼时间.");

        UserModel loginUser = userMapper.selectById(userId);
        if(loginUser == null){
            return null;
        }

        // 获取50米短跑时间
        Double meterDashTime = Double.parseDouble(loginUser.getMeterDashTime());
        // 获取引体向上的次数
        Integer pullUpTimes = Integer.parseInt(loginUser.getPullUpTimes());
        // 获取俯卧撑的次数
        Integer pushUpTimes = Integer.parseInt(loginUser.getPushUpTimes());

        Double meterDashScore = (HealthStandardValue.METER_DASH_TIMER - meterDashTime) * 50;
        Double pullUpScore = (pullUpTimes - HealthStandardValue.PULL_UP_TIMES) * 0.5;
        Double pushUpScore = (pushUpTimes - HealthStandardValue.PUSH_UP_TIMES) * 0.5;

        Integer healthLevelInfo = this.getMointLevel(meterDashScore, pullUpScore, pushUpScore);
        return motionMap.get(healthLevelInfo);
    }

    @Override
    public String foodRecommend(Integer userId) {
        String season = getNowSeason();
        List<String> illHealthInfo = getIllHealthInfo(userId);
        LambdaQueryWrapper<FoodInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<FoodInfo> foodInfos = new ArrayList<>();
        StringBuilder returnStr = new StringBuilder();

        for(String ill : illHealthInfo){
            if(ill.equals("bmi")){
                lambdaQueryWrapper.or().eq(FoodInfo::getWeightControlFlag, 1);
            }
            if(ill.equals("血压")){
                lambdaQueryWrapper.or().eq(FoodInfo::getBloodPressureControlFlag, 1);
            }
            if(ill.equals("血脂")){
                lambdaQueryWrapper.or().eq(FoodInfo::getBloodLipidControlFlag, 1);
            }
            if(ill.equals("血糖")){
                lambdaQueryWrapper.or().eq(FoodInfo::getBloodGlucoseControlFlag, 1);
            }
        }

        lambdaQueryWrapper.eq(FoodInfo::getSeason, season);
        foodInfos = foodInfoMapper.selectList(lambdaQueryWrapper);

        // 如果健康指标正常, 或者可推荐的食物操作4个, 则推荐本季节的前4个蔬菜
        if(illHealthInfo.isEmpty() || foodInfos.size() > 4){
            foodInfos = foodInfos.subList(0, 4);
        }


        for(FoodInfo foodInfo : foodInfos){
            returnStr.append(foodInfo.getFoodName()).append(": ").append(foodInfo.getSeason()).append("菜肴, ").append(foodInfo.getIntroduction()).append(";<br><br>");
        }

        return returnStr.toString();
    }

    public HealthGrade evaluateHealth(Double bmiScore, Double hypotensiveScore, Double bloodGlucoseScore, Double bloodLipidScore) {
        double totalScore = bmiScore + hypotensiveScore + bloodGlucoseScore + bloodLipidScore;

        for (HealthGrade grade : HealthGrade.values()) {
            if (grade.includesScore(totalScore)) {
                return grade;
            }
        }

        return null;
    }

    public MotionGrade evaluateHealth(Double meterScore, Double pullUpScore, Double pushUpScore) {
        double totalScore = meterScore + pullUpScore + pushUpScore;

        for (MotionGrade grade : MotionGrade.values()) {
            if (grade.includesScore(totalScore)) {
                return grade;
            }
        }

        return null;
    }

    private String getNowSeason(){
        LocalDate now = LocalDate.now();
        int month = now.getMonthValue();
        int day = now.getDayOfMonth();

        if (month == 12 && day >= 22 || month == 1 || month == 2) {
            return "冬季";
        } else if (month == 3 && day < 21 || month == 4 || month == 5) {
            return "春季";
        } else if (month == 3 && day >= 21 && month == 5 && day < 22 || month == 6 || month == 7 || month == 8) {
            return "夏季";
        } else if (month == 9 && day >= 23 || month == 10 || month == 11) {
            return "秋季";
        }
        return null;
    }

    private List<String> getIllHealthInfo(Integer userId){
        UserModel loginUser = userMapper.selectById(userId);
        List<String> illList = new ArrayList<>();
        // BMI
        Double bmi = loginUser.getBMI();
        // 低血压值
        int hypotensiveValue = Integer.parseInt(loginUser.getHypotensiveValue());
        // 高血压值
        int hypertensiveValue = Integer.parseInt(loginUser.getHypertensiveValue());
        // 血糖值
        double bloodGlucoseValue = Double.parseDouble(loginUser.getBloodGlucoseValue());
        // 血脂值
        double bloodLipidValue = Double.parseDouble(loginUser.getBloodLipidValue());

        if(60 > hypotensiveValue || 80 < hypotensiveValue
                || 90 > hypertensiveValue || 120 < hypertensiveValue) {
            illList.add("血压");
        }
        if(!(18.5 <= bmi && bmi < 24)){
            illList.add("bmi");
        }
        if(!(3.9 <= bloodGlucoseValue && bloodGlucoseValue <= 6.1)){
            illList.add("血糖");
        }
        if(!(5.18 <= bloodLipidValue && bloodLipidValue <= 5.20)){
            illList.add("血脂");
        }

        return illList;
    }

    private int getMointLevel(double meterDashScore, double pullUpScore, double pushUpScore){
        MotionGrade motionGrade = evaluateHealth(meterDashScore, pullUpScore, pushUpScore);
        Integer motionLevel = null;
        switch (motionGrade){
            case IDEAL:
                motionLevel = 1;
                break;
            case GOOD:
                motionLevel = 2;
                break;
            case MODERATELY_UNHEALTHY:
                motionLevel = 3;
                break;
            case MILDLY_UNHEALTHY:
                motionLevel = 4;
                break;
            case SERIOUSLY_UNHEALTHY:
                motionLevel = 5;
                break;
            case HIGH_RISK:
                motionLevel = 6;
                break;
        }
        return motionLevel;
    }
}
